import re

from bilibili_danmu_analysis.config.mongo_config import MongoConfig
from bilibili_danmu_analysis.config.redis_config import RedisConfig
from bilibili_danmu_analysis.utils import Utils
import  jieba

class AnalysisDao:
    def __init__(self):
        self.mongo_config = MongoConfig()
        self.mongo_collection = self.mongo_config.get_mongo_collection()
        self.redis_config = RedisConfig().get_redis_client()
        self.utils=Utils()

    def close_connections(self):
        self.mongo_config.close_mongo_client()
        self.redis_config.close()

    def verify_bvid_exits(self, bvid):
        try:
            message = self.redis_config.exists(f"danmaku:{bvid}")
            return message
        except Exception as e:
            return {"code": 500, "error": f"An error occurred:{str(e)}"}

    def get_bvid_info(self, bvid):
        try:
            # 输入验证：确保 bvid 是字符串类型
            if not isinstance(bvid, str) or not bvid.strip():
                raise ValueError("Invalid bvid: Expected a non-empty string")
            elif not self.verify_bvid_exits(bvid):
                return {"code": 404, "message": "bvid not crawled yet"}

            message_cursor = self.mongo_collection.find({'bvid': bvid})
            message_list = list(message_cursor)
            if not message_list:
                return {"code": 404, "message": "No data found for the given bvid"}
            return {"code": 200, "data": message_list}
        except Exception as e:
            return {"code": 500, "error": f"An error occurred:{str(e)}"}
    def get_bvid_danmu(self, bvid):
        try:
            msg=self.get_bvid_info(bvid)
            if msg["code"] != 200 or not msg["data"]:
                return msg
            danmu_list=[]
            for item in msg["data"]:
                danmu_list.append(item["text"])
            return {"code": 200, "data": danmu_list}
        except KeyError as e:
            return {"code": 500, "error": f"Key error occurred: {str(e)}"}
        except Exception as e:
            return {"code": 500, "error": f"An error occurred:{str(e)}"}
    def cut_bvid_danmu_word(self, bvid):
        try:
            msg=self.get_bvid_danmu(bvid)
            if msg["code"] != 200 or not msg["data"]:
                return msg

            word_list=[]
            for item in msg["data"]:
                words= jieba.cut(item, cut_all=False)
                word_list.extend(words)
            return {"code": 200, "data": word_list}
        except KeyError as e:
            return {"code": 500, "error": f"Key error occurred: {str(e)}"}
        except Exception as e:
            return {"code": 500, "error": f"An unexpected error occurred: {str(e)}"}
    def statisic_danmu_word(self, bvid):
        try:
            # 获取弹幕分词结果
            msg = self.cut_bvid_danmu_word(bvid)
            # 如果返回值不正确或数据为空，直接返回
            if msg["code"] != 200 or not msg["data"]:
                return msg
            chinese_pattern = re.compile(r'^[\u4e00-\u9fa5]+$')
            word_dict = {}
            for item in msg["data"]:
                # 过滤非中文字符和单字
                if chinese_pattern.match(item) and len(item) > 1:
                    word_dict[item] = word_dict.get(item, 0) + 1
            word_dict = dict(sorted(word_dict.items(), key=lambda item: item[1], reverse=True))
            return {"code": 200, "data": word_dict}
        except KeyError as e:
            return {"code": 500, "error": f"Key error occurred: {str(e)}"}
        except Exception as e:
            return {"code": 500, "error": f"An unexpected error occurred: {str(e)}"}

    def get_top_keywords(self,bvid):
        try:
            msg=self.statisic_danmu_word(bvid)
            if msg["code"] != 200 or not msg["data"]:
                return msg
            return {"code": 200, "data": list(msg["data"].keys())[:10]}
        except Exception as e:
            return {"code": 500, "error": f"An error occurred:{str(e)}"}

    def get_bvid_danmu_count(self, bvid):
        try:
            msg=self.get_bvid_info(bvid)
            if msg["code"]==200:
                return {"code": 200, "data": len(msg["data"])}

            return msg
        except Exception as e:
            return {"code": 500, "error": f"An error occurred:{str(e)}"}

    def get_bvid_danmu_user(self, bvid):
        try:
            msg=self.get_bvid_info(bvid)
            if msg["code"] != 200 or not msg["data"]:
                return msg
            user_dict= {}
            for item in msg["data"]:
                users= item["user_id"]
                if users in user_dict:
                    user_dict[users] += 1
                else:
                    user_dict[users] = 1
            user_dict = dict(sorted(user_dict.items(), key=lambda item: item[1], reverse=True))
            return {"code": 200, "data": user_dict}
        except Exception as e:
            return {"code": 500, "error": f"An error occurred:{str(e)}"}

    def get_most_active_user(self, bvid):
        try:
            msg=self.get_bvid_danmu_user(bvid)
            if msg["code"] != 200 or not msg["data"]:
                return msg
            return {"code": 200, "data": list(msg["data"].keys())[0]}
        except Exception as e:
            return {"code": 500, "error": f"An error occurred:{str(e)}"}

    def count_users(self, bvid):
        try:
            msg=self.get_bvid_danmu_user(bvid)
            if msg["code"] != 200 or not msg["data"]:
                return msg
            user_set = set()
            for item in msg["data"]:
                user_set.add(item)
            return {"code": 200, "data": len(user_set)}
        except Exception as e:
            return {"code": 500, "error": f"An error occurred:{str(e)}"}

    def get_bvid_timestamp(self, bvid):
        try:
            msg=self.get_bvid_info(bvid)
            if msg["code"] != 200 or not msg["data"]:
                return msg
            time_dict = {}
            for item in msg["data"]:
                timestamp = int(item["timestamp"])
                timestamp=self.utils.tramsform_timestamp(timestamp)
                if timestamp in time_dict:
                    time_dict[timestamp]= time_dict[timestamp]+1
                else:
                    time_dict[timestamp]=1
            return {"code": 200, "data": time_dict}
        except Exception as e:
            return {"code": 500, "error": f"An error occurred:{str(e)}"}

    def get_bvid_dict(self, bvid):
        try:
            bvid_dict = {}
            bvid_dict["danmu_count"] = self.get_bvid_danmu_count(bvid).get("data")
            bvid_dict["user_count"] = self.count_users(bvid).get("data")
            bvid_dict["avg_length"] = self.get_bvid_danmu_count(bvid).get("data") / self.count_users(bvid).get("data")
            bvid_dict["most_active_user"] = self.get_most_active_user(bvid).get("data")
            bvid_dict["top_keywords"] = self.get_top_keywords(bvid).get("data")
            return {"code": 200, "data": bvid_dict}
        except Exception as e:
            return {"code": 500, "error": f"An error occurred:{str(e)}"}

if __name__ == "__main__":
    dao = AnalysisDao()
    bvid="BV11NoCYmEkP"
    msg=dao.get_bvid_dict(bvid)
    print(msg)
    dao.close_connections()
